package com.xuecheng.search.service;

import com.alibaba.fastjson.JSON;
import com.xuecheng.framework.domain.course.CoursePub;
import com.xuecheng.framework.domain.course.response.TeachplanMediaPub;
import com.xuecheng.framework.domain.media.response.MediaCode;
import com.xuecheng.framework.domain.search.CourseSearchParam;
import com.xuecheng.framework.exception.CustomExcetionCast;
import com.xuecheng.framework.model.response.CommonCode;
import com.xuecheng.framework.model.response.QueryResponseResult;
import com.xuecheng.framework.model.response.QueryResult;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
//import org.springframework.beans.BeanUtils;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PathVariable;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchService {
    @Autowired
    RestHighLevelClient restHighLevelClient;
    @Autowired
    RestClient restClient;

    /**
     * @Description: 提供搜索功能
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Value("${xuecheng.course.index}")
    private String indices;
    @Value("${xuecheng.course.type}")
    private String type;

    public QueryResponseResult searchIndex(Integer page, Integer size, CourseSearchParam courseSearchParam) {
//        创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(indices);
//        创建搜索构建源对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        if (page == 0 || page == null) {
            page = 1;
        }
        if (size == 0 || size == null) {
            size = 10;
        }
//        设置分页搜索
        int cur = (page - 1) * size;
        searchSourceBuilder.from(cur);
        searchSourceBuilder.size(size);
//        设置排序方式
//        设置高亮显示
        String filter = courseSearchParam.getFilter();
        String grade = courseSearchParam.getGrade();
        String keyword = courseSearchParam.getKeyword();
        String mt = courseSearchParam.getMt();
        String st = courseSearchParam.getSt();
        Float price_max = courseSearchParam.getPrice_max();
        Float price_min = courseSearchParam.getPrice_min();
        String sort = courseSearchParam.getSort();
        //            设置高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font class='eslight'>");
        highlightBuilder.postTags("</font>");
//        设置搜索条件方式
        //        bool查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//          模糊匹配查询
        if (!StringUtils.isEmpty(keyword)) {
            MultiMatchQueryBuilder name = QueryBuilders.multiMatchQuery(keyword, "name", "description", "teachplan").minimumShouldMatch("70%").field("name", 5);
            highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
            highlightBuilder.fields().add(new HighlightBuilder.Field("description"));
            highlightBuilder.fields().add(new HighlightBuilder.Field("teachplan"));
//            searchSourceBuilder.query(name);
            searchSourceBuilder.highlighter(highlightBuilder);
            boolQueryBuilder.must(name);
        }
//        精确查询
        if (!StringUtils.isEmpty(grade)) {
            TermQueryBuilder grade1 = QueryBuilders.termQuery("grade", grade);
            boolQueryBuilder.filter(grade1);
        }
        if (!StringUtils.isEmpty(mt)) {
            TermQueryBuilder mt1 = QueryBuilders.termQuery("mt", mt);
            boolQueryBuilder.filter(mt1);
        }
        if (!StringUtils.isEmpty(st)) {
            TermQueryBuilder st1 = QueryBuilders.termQuery("st", st);
            boolQueryBuilder.filter(st1);
        }
//        范围查询
        if (price_max != null && price_min != null && price_max != 0) {
            RangeQueryBuilder priceMin = QueryBuilders.rangeQuery("price").gt(price_min);
            RangeQueryBuilder priceMax = QueryBuilders.rangeQuery("price").gt(price_max);
            boolQueryBuilder.filter(priceMin);
            boolQueryBuilder.filter(priceMax);

        }
        SearchSourceBuilder sourceBuilder = searchSourceBuilder.query(boolQueryBuilder);
//         搜索源请求设置搜索源构建对象
        SearchRequest source = searchRequest.source(sourceBuilder);
//        进行搜索
        SearchResponse searchResponse = null;
        try {
            searchResponse = restHighLevelClient.search(source);
        } catch (IOException e) {
            e.printStackTrace();
        }
//        得到搜索结果
        SearchHits hits = searchResponse.getHits();
//        总记录数
        long totalHits = hits.getTotalHits();
        SearchHit[] searchHits = hits.getHits();
        List<CoursePub> list = new ArrayList<>();
        if (searchHits != null) {
            for (SearchHit hit : searchHits
            ) {
                Map<String, Object> hitSourceAsMap = hit.getSourceAsMap();
                String name = (String) hitSourceAsMap.get("name");
                String description = (String) hitSourceAsMap.get("description");
                String teachplane = (String) hitSourceAsMap.get("teachplane");
                Double price = (Double) hitSourceAsMap.get("price");
                String pic = (String) hitSourceAsMap.get("pic");
                String id = (String) hitSourceAsMap.get("id");
//                取出高亮内容
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField nameField = highlightFields.get("name");
                HighlightField descriptionField = highlightFields.get("description");
                HighlightField teachplaneField = highlightFields.get("teachplane");
                StringBuffer stringBuffername = new StringBuffer();
                StringBuffer stringBufferdescription = new StringBuffer();
                StringBuffer stringBufferteachplane = new StringBuffer();
//                高亮内容
                name = getHighlight(nameField, name, stringBuffername);
                description = getHighlight(descriptionField, description, stringBuffername);
                teachplane = getHighlight(teachplaneField, teachplane, stringBuffername);


                CoursePub coursePub = new CoursePub();

                coursePub.setName(name);
                coursePub.setDescription(description);
                coursePub.setTeachplan(teachplane);
                coursePub.setPic(pic);
                coursePub.setPrice(price);
                coursePub.setId(id);
                list.add(coursePub);
            }
        }

        QueryResult queryResult = new QueryResult();
        queryResult.setTotal(totalHits);
        queryResult.setList(list);
        return new QueryResponseResult(CommonCode.SUCCESS, queryResult);
    }

    /**
     * @Description: 获取高亮内容遍历
     * @Param: HighlightField name1,@原始内容String name,StringBuffer stringBuffer
     * @return: 高亮字符串
     * @Author: Mr.Yuan
     * @Date:
     */
    public String getHighlight(HighlightField name1, String name, StringBuffer stringBuffer) {
        if (name1 != null) {
            Text[] fragments = name1.getFragments();
            for (Text text : fragments
            ) {
                stringBuffer.append(text);
            }
            name = stringBuffer.toString();
        }
        return name;
    }

    ;

    /**
     * @Description: 根据id查询课程全部信息
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    public Map<String, CoursePub> findbyId(String id) {
//        创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest(indices);
//        设置索引类型
        searchRequest.types(type);
//        创建搜索构建者对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置搜索方式
        searchSourceBuilder.query(QueryBuilders.termsQuery("_id", id));
//        进行搜索
        SearchRequest source = searchRequest.source(searchSourceBuilder);
        Map<String, CoursePub> map = new HashMap<>();
        try {
            SearchResponse searchResponse = restHighLevelClient.search(source);
//            获取结果
            SearchHits hits = searchResponse.getHits();
            SearchHit[] hitsHits = hits.getHits();
            long totalHits = hits.getTotalHits();

            if (hitsHits != null) {
                for (SearchHit sh : hitsHits
                ) {
                    CoursePub coursePub = new CoursePub();
                    Map<String, Object> sourceAsMap = sh.getSourceAsMap();
                    String courseId = (String) sourceAsMap.get("id");
                    String name = (String) sourceAsMap.get("name");
                    String grade = (String) sourceAsMap.get("grade");
                    String charge = (String) sourceAsMap.get("charge");
                    String pic = (String) sourceAsMap.get("pic");
                    String description = (String) sourceAsMap.get("description");
                    String teachplan = (String) sourceAsMap.get("teachplan");

                    coursePub.setCharge(charge);
                    coursePub.setGrade(grade);
                    coursePub.setTeachplan(teachplan);
                    coursePub.setDescription(description);
                    coursePub.setId(courseId);
                    coursePub.setName(name);
                    coursePub.setPic(pic);
                    map.put(courseId, coursePub);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * @Description: 根据课程id查询媒资信息
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Value("${xuecheng.course.index_media}")
    String indexMedia;
    public List<TeachplanMediaPub> findTeachplanMedia(String teachplanId) {
        if (StringUtils.isEmpty(teachplanId)) {
            throw CustomExcetionCast.getCusException(CommonCode.INVALIDPARAM);
        }
//        从索引库中查询
        SearchRequest searchRequest = new SearchRequest(indexMedia);
        searchRequest.types(type);
//        创建搜索源构建者对象
        SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
//        设置搜索方式
        searchSourceBuilder.query(QueryBuilders.termsQuery("teachplan_id",teachplanId));
//        执行搜索
        SearchRequest source = searchRequest.source(searchSourceBuilder);
        List<TeachplanMediaPub> list=new ArrayList();
        try {
            SearchResponse searchResponse = restHighLevelClient.search(source);
            SearchHits hits = searchResponse.getHits();
            SearchHit[] hitsHits = hits.getHits();
            if(hitsHits!=null){
                for (SearchHit sh:hitsHits
                     ) {
                    Map<String, Object> sourceAsMap = sh.getSourceAsMap();
                    TeachplanMediaPub teachplanMediaPub=new TeachplanMediaPub();

                    teachplanMediaPub.setCourseId((String) sourceAsMap.get("courseid"));
                    teachplanMediaPub.setMediaFileOriginalName((String) sourceAsMap.get("media_fileoriginalname"));
                    teachplanMediaPub.setMediaId((String) sourceAsMap.get("media_id"));
                    teachplanMediaPub.setMediaUrl((String) sourceAsMap.get("media_url"));
                    teachplanMediaPub.setTeachplanId((String) sourceAsMap.get("teachplan_id"));
                    list.add(teachplanMediaPub);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw  CustomExcetionCast.getCusException(CommonCode.FAIL);
        }

        return list;
    }
}
